/**
 * Copyright 2020 Inc.
 **/
package com.myz.buddy;


import com.myz.buddy.interceptor.TimeInterceptor;
import net.bytebuddy.agent.builder.AgentBuilder;
import net.bytebuddy.description.type.TypeDescription;
import net.bytebuddy.dynamic.DynamicType;
import net.bytebuddy.implementation.MethodDelegation;
import net.bytebuddy.matcher.ElementMatchers;
import net.bytebuddy.utility.JavaModule;
import net.bytebuddy.utility.nullability.MaybeNull;

import java.lang.instrument.Instrumentation;
import java.security.ProtectionDomain;


/**
 * 定义premain方法
 *
 * @author maoyz0621 on 2020/11/23
 * @version v1.0
 */
public class PreMainAgentProjectName {

    /**
     * @param agentArgs -javaagent 命令携带的参数
     * @param inst
     */
    public static void premain(String agentArgs, Instrumentation inst) {
        System.out.println("11111111111111111");

        String projectName = agentArgs;
        if (projectName == null || "".equals(projectName)) {
            return;
        }
        AgentBuilder agentBuilder = new AgentBuilder.Default()
                .ignore(ElementMatchers.nameStartsWith("net.bytebuddy.")
                        .or(ElementMatchers.nameStartsWith("org.slf4j."))
                        .or(ElementMatchers.nameStartsWith("org.groovy."))
                        .or(ElementMatchers.nameContains("javassist"))
                        .or(ElementMatchers.nameContains(".asm."))
                        .or(ElementMatchers.nameContains(".reflectasm."))
                        .or(ElementMatchers.nameStartsWith("sun.reflect"))
                        .or(ElementMatchers.isSynthetic()));
        // 构建builder
        agentBuilder.type(ElementMatchers.nameStartsWith(projectName)
                        .and(ElementMatchers.not(ElementMatchers.isAnnotation()))  // 排除注解
                        .and(ElementMatchers.not(ElementMatchers.isInterface()))  // 排除接口
                        .and(ElementMatchers.not(ElementMatchers.isEnum()))  // 排除枚举
                ) // 指定需要拦截的类
                .transform(new Transformer(projectName))
                .with(AgentBuilder.RedefinitionStrategy.RETRANSFORMATION)
                .with(new Listener())
                .installOn(inst);
        Runtime.getRuntime().addShutdownHook(new Thread());
    }

    private static class Transformer implements AgentBuilder.Transformer {

        private String projectName;

        public Transformer(String projectName) {
            this.projectName = projectName;
        }

        /**
         * @param builder
         * @param typeDescription
         * @param classLoader
         * @param module
         * @param protectionDomain
         * @return
         */
        @Override
        public DynamicType.Builder<?> transform(DynamicType.Builder<?> builder,
                                                TypeDescription typeDescription,
                                                @MaybeNull ClassLoader classLoader,
                                                @MaybeNull JavaModule module,
                                                ProtectionDomain protectionDomain) {
            // ElementMatchers.<MethodDescription>any()
            return builder
                    .method(ElementMatchers.not(ElementMatchers.isStatic())
                            .and(ElementMatchers.not(ElementMatchers.isPrivate()))
                    )  // 方法拦截
                    .intercept(MethodDelegation.to(new TimeInterceptor())); // 授权拦截器
        }
    }

    private static class Listener implements AgentBuilder.Listener {

        @Override
        public void onDiscovery(String typeName, ClassLoader classLoader, JavaModule module, boolean loaded) {

        }

        @Override
        public void onTransformation(TypeDescription typeDescription, ClassLoader classLoader, JavaModule module, boolean loaded, DynamicType dynamicType) {

        }

        @Override
        public void onIgnored(TypeDescription typeDescription, ClassLoader classLoader, JavaModule module, boolean loaded) {

        }

        @Override
        public void onError(String typeName, ClassLoader classLoader, JavaModule module, boolean loaded, Throwable throwable) {

        }

        @Override
        public void onComplete(String typeName, ClassLoader classLoader, JavaModule module, boolean loaded) {

        }
    }
}